package cmd

import (
	"encoding/gob"
	"fmt"
	"io"
	"net"

	"github.com/donnie4w/go-logger/logger"
)

type Conn struct {
	server *CmdSvr
	rwc    net.Conn
	dce    *gob.Decoder
	dse    *gob.Encoder
}

func newConn(svr *CmdSvr, rwc net.Conn) *Conn {
	return &Conn{
		server: svr,
		rwc:    rwc,
		dce:    gob.NewDecoder(rwc),
		dse:    gob.NewEncoder(rwc),
	}
}

func (c *Conn) serve() {
	remoteAddr := c.Addr()
	defer func() {
		recover()
		logger.Debug(fmt.Sprintf("CmdSvr connection close %s", remoteAddr))
		c.rwc.Close()
	}()

	logger.Info(fmt.Sprintf("CmdSvr connect %s", remoteAddr))

	for {
		select {
		case <-c.server.exitChan:
			return
		default:
		}

		p := &ProtoDce{}
		e := c.dce.Decode(p)
		if e != nil {
			if e != io.EOF {
				if ne, ok := e.(net.Error); !ok && !ne.Temporary() {
					logger.Error(fmt.Sprintf("CmdSvr recv error: %s, addr: %s", e.Error(), remoteAddr))
				}
			}
			break
		}

		e = c.server.dceHandler(c, p)
		if e != nil {
			logger.Error(fmt.Sprintf("CmdSvr handler error: %s, addr: %s", e.Error(), remoteAddr))
			break
		}
	}
}

func (c *Conn) Send(p *ProtoDse) error {
	e := c.dse.Encode(p)
	if e != nil {
		logger.Error(fmt.Sprintf("CmdSvr send error: %s, addr: %s", e.Error(), c.Addr()))
	}
	return e
}

func (c *Conn) Addr() string {
	return c.rwc.RemoteAddr().String()
}
